import * as THREE from "three"
import Matrix from "../three/Matrix"
import Vectors from "../three/Vectors"
import a from "./7170"
import funcUtil from "../utils/func.util"

const l = new THREE.Frustum()
const c = new Matrix()

const h = {
  fromVisionVector: (e: { z: number; w?: number; x: number; y: number }) => {
    return new THREE.Vector3(e.x, e.z, -e.y)
  },
  toVisionVector: (e: { z: number; w?: number; x: number; y: number }) => {
    return new THREE.Vector3(e.x, -e.z, e.y)
  },
  fromVisionQuaternion: (e: { z: number; w?: number; x: number; y: number }) => {
    return new THREE.Quaternion(e.x, e.z, -e.y, e.w).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), a.Id(90)))
  },
  fromVisionCameraQuaternion: (e: { z: number; w?: number; x: number; y: number }) => {
    return new THREE.Quaternion(-e.x, -e.z, e.y, -e.w).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), a.Id(90)))
  },
  toVisionQuaternion: (e: { z: number; w?: number; x: number; y: number }) => {
    const t = new THREE.Quaternion(e.x, e.y, e.z, e.w).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), a.Id(-90)))
    return t.set(t.x, -t.z, t.y, t.w), t
  },
  toVisionCameraQuaternion: (e: { z: number; w?: number; x: number; y: number }) => {
    return new THREE.Quaternion(e.x, -e.z, e.y, e.w).multiply(new THREE.Quaternion(-0.70710678118, 0, 0, 0.70710678118))
  }
}

const getPosition = function (e: THREE.Vector3) {
  return new THREE.Vector3(-e.x, e.y, e.z)
}
const u = function (e: { z: number; w: number; x: number; y: number }) {
  return new THREE.Quaternion(e.z, e.w, e.x, e.y)
}
const p = (e: number) => {
  return Math.cos(a.Id(e / 2))
}
function m(e: number, t: number, i: number) {
  return Math.abs(t - e) <= i ? t : e + Math.sign(t - e) * i
}
const g = (e: THREE.Quaternion, t: THREE.Quaternion) => {
  const i = new THREE.Vector3(0, 0, -1)
  return i.clone().applyQuaternion(e).angleTo(i.clone().applyQuaternion(t))
}
const insideBounds = (position: THREE.Vector3, t: THREE.Quaternion, i: Matrix, n: THREE.Box3) => (
  c.identity().makeRotationFromQuaternion(t).setPosition(position),
  c.getInverse(c),
  c.premultiply(i),
  l.setFromProjectionMatrix(c.asThreeMatrix4()),
  l.intersectsBox(n)
)
const v = (e: THREE.Box3) => {
  const t = e.getSize(new THREE.Vector3())
  const i = Math.max(t.x, t.y, t.z)
  return new THREE.Box3().setFromCenterAndSize(e.getCenter(new THREE.Vector3()), new THREE.Vector3(i, i, i))
}
const y = (e: { min: { x: number; y: number; z: number }; max: { x: number; y: number; z: number } }, t: string | any[]) => {
  if (t.length < 8) throw new Error("getPointsFromBox3: Result array to small!")
  t[0].copy(e.min)
  t[1].copy(e.min)
  t[1].x = e.max.x
  t[2].copy(e.min)
  t[2].y = e.max.y
  t[3].copy(e.min)
  t[3].z = e.max.z
  t[4].copy(e.max)
  t[5].copy(e.max)
  t[5].x = e.min.x
  t[6].copy(e.max)
  t[6].y = e.min.y
  t[7].copy(e.max)
  t[7].z = e.min.z
}
const b = (e: number, t: number, i: number, n: number, s: number) => (s - n) * ((e - t) / (i - t)) + n
const S = (e: number, t: number, i: number, n: number, s: number) => {
  const r = b(e, t, i, n, s)
  return funcUtil.getMax(r, n, s)
}
function E(e: { x: number; y: number; z: number }) {
  return 0 === e.x && 0 === e.y && 0 === e.z
}
const getRotation = (() => {
  const e = new THREE.Vector3()
  const t = new THREE.Matrix4()
  return (i: THREE.Quaternion) =>
    E(i) ? i.clone() : (e.copy(Vectors.FORWARD).applyQuaternion(i), t.lookAt(Vectors.ZERO, e, Vectors.UP), new THREE.Quaternion().setFromRotationMatrix(t))
})()
const w = (() => {
  const e = new THREE.Vector3()
  const t = new THREE.Matrix4()
  return (i: THREE.Quaternion, n: THREE.Quaternion) =>
    E(i) ? n.copy(i) : (e.copy(Vectors.FORWARD).applyQuaternion(i).setY(0).normalize(), t.lookAt(Vectors.ZERO, e, Vectors.UP), n.setFromRotationMatrix(t))
})()
const _ = (() => {
  const e = new THREE.Vector3()
  const t = new THREE.Ray()
  return (i: THREE.Vector3, s: THREE.Vector3, r: number, o: THREE.Vector3 = new THREE.Vector3()) => {
    t.origin.copy(i)
    t.lookAt(s)
    return o.copy(t.at(r, e))
  }
})()
const M = (() => {
  const e = new THREE.Vector3()
  const t = new THREE.Ray()
  return (i: THREE.Vector3, s: THREE.Vector3, r: number, o: THREE.Vector3 = new THREE.Vector3()) => {
    t.set(i, s)
    return o.copy(t.at(r, e))
  }
})()
export default {
  ep: h,
  gj: getPosition,
  EV: u,
  tf: p,
  r_: m,
  zW: g,
  cb: insideBounds,
  rj: v,
  jB: y,
  et: b,
  dS: S,
  Z: getRotation,
  Rq: w,
  Xe: _,
  Xv: M
}
